//ASFview version 1.1
/*
Changelog: 0.9: Ah, I found it! The nightmare bug, the one that just refused to be found, the single tiny flaw
                that resulted in suspending work for *years* while I learnt to program. Such a simple thing. I had
                two parameters the wrong way round in a fread.
                Thats it, the program can now handle *any* properly formatted ASF, WMA or WMV file without going
                into loop. All thats left is to handle every object type correctly.
           1.0: Minor changes.
           1.1: A submitted patch was added to support DRM objects. This is something I had been meaning to do, but I didn't think anyone used this program!
           1.5: After many years of disinterest, rereleasing - this time with the code made a little better, updated
                with current standards, and with the politcal ramblings of my former student-idealist self removed.
*/
#include <stdio.h>
//#include <stdint.h>
#define uint64_t unsigned long long
#define uint32_t unsigned int
#define uint16_t unsigned short

void guidfix(unsigned char GUID[16]);
void header_object();
void content_description_object();
void Extended_Content_Description_Object();
void Stream_Bitrare_Properties_Object();
void File_Properties_Object();
void Header_Extension_Object();
void Stream_Properties_Object();
void Stream_Bitrate_Properties_Object();
void hexdump(uint64_t remaining);
void Codec_List_Object();
void unicode_print(int remaining);
void Marker_Object();
void Script_Command_Object();
void Language_List_Object();
void Padding_Object();
void DRMv1_Header_Object();
void DRMv2_Header_Object();
void Unknown_Object();


FILE *filehandle; //file handle
//These are used for reading the ASF:
//Making them global is easier than locals for every function
unsigned char GUID[16]; //128-bit
unsigned char qword[8]; //64-bit
uint64_t int64; //64-bit for integer data.
unsigned char dword[4]; //32-bit
uint32_t int32; //32-bit for integer data
unsigned char word[2];//16-bit
uint16_t int16;
unsigned char byte; //8-bit

main(int argc, char *argv[])
{
    unsigned char *filename; //guess what this holds.
    unsigned int n; //loop counter
    unsigned int object=0; //A more specialised loop counter
    unsigned int recognised; //The list of ifs below is the spagetii equivilent of a case. But I cant case arrays!

    //These const arrays store GUIDs to identify objects
    const unsigned char ASF_header_object[16]=                       {0x75, 0xB2, 0x26, 0x30, 0x66, 0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C};
    const unsigned char ASF_data_object[16]=                         {0x75, 0xB2, 0x26, 0x36, 0x66, 0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C};
    const unsigned char ASF_simple_index_object[16]=                 {0x33, 0x00, 0x08, 0x90, 0xE5, 0xB1, 0x11, 0xCF, 0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB};
    const unsigned char ASF_Content_Description_Object[16]=          {0x75, 0xB2, 0x26, 0x33, 0x66 ,0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C};
    const unsigned char ASF_Extended_Content_Description_Object[16]= {0xD2, 0xD0, 0xA4, 0x40, 0xE3, 0x07, 0x11, 0xD2, 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5e, 0xA8, 0x50};
    const unsigned char ASF_Stream_Bitrate_Properties_Object[16]=    {0x7B, 0xF8, 0x75, 0xCE, 0x46, 0x8D, 0x11, 0xD1, 0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2};
    const unsigned char ASF_File_Properties_Object[16]=              {0x8C, 0xAB, 0xDC, 0xA1, 0xA9, 0x47, 0x11, 0xCF, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65};
    const unsigned char ASF_Data_Object[16]=                         {0x75, 0xB2, 0x26, 0x36, 0x66, 0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C};
    const unsigned char ASF_Header_Extension_Object[16]=             {0x5F, 0xBF, 0x03, 0xB5, 0xA9, 0x2E, 0x11, 0xCF, 0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65};
    const unsigned char ASF_Stream_Properties_Object[16]=            {0xB7, 0xDC, 0x07, 0x91, 0xA9, 0xB7, 0x11, 0xCF, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65};
    const unsigned char ASF_Codec_List_Object[16]=                   {0x86, 0xD1, 0x52, 0x40, 0x31, 0x1D, 0x11, 0xD0, 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6};
    const unsigned char ASF_Marker_Object[16]=                       {0xF4, 0x87, 0xCD, 0x01, 0xA9, 0x51, 0x11, 0xCF, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65};
    const unsigned char ASF_Script_Command_Object[16]=               {0x1E, 0xFB, 0x1A, 0x30, 0x0B, 0x62, 0x11, 0xD0, 0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6};
    const unsigned char ASF_Language_List_Object[16]=                {0x7C, 0x43, 0x46, 0xa9, 0xef, 0xe0, 0x4B, 0xFC, 0xB2, 0x29, 0x39, 0x3e, 0xde, 0x41, 0x5c, 0x85};
    const unsigned char ASF_Padding_Object[16]=                      {0x18, 0x06, 0xD4, 0x74, 0xCA, 0xDF, 0x45, 0x09, 0xA4, 0xBA, 0x9A, 0xAB, 0xCB, 0x96, 0xAA, 0xE8};
    const unsigned char ASF_DRMv1_Header_Object[16]=                 {0x22, 0x11, 0xB3, 0xFB, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E};
    const unsigned char ASF_DRMv2_Header_Object[16]=                 {0x29, 0x8A, 0xE6, 0x14, 0x26, 0x22, 0x4C, 0x17, 0xB9, 0x35, 0xDA, 0xE0, 0x7E, 0xE9, 0x28, 0x9c};

    if (argc<=1)
    {
        //an empty command line - fprint help and my rant
        printf("ASFview 1.5\n");
        printf("Takes an ASF header apart and displays whatever it finds. Also works on WMA and WMV files, as these are internally identical to ASF.\n");
        printf("asfview <file.asf>\n\n");

        printf("Other options are:\n");
        printf("-n             Read release notes\n");
        return(0);
    }
    filename=argv[1];
    if (filename[0]=='-'&&argc==2)
    {
        if (filename[1]=='n')
        {
            printf("notes:\n\nASFView can read the header information from most ASF, WMA and WMV files,\n"
                   "but was written using only the ASF spec. If you have a file it does not read correctly,\n"
                   "contact me. I will attempt to find the problem and fix it.\n\n"
                   "The output is formatted for linux. Althrough I have produced a DOS port, the output wraps.\n"
                   "Just pipe the output to a text file to make it more readable.\n\n"
                   "ASFView source code is published, but I wrote it to improve my programing skill,\n"
                   "so the code is messy. You have been warned :-)\n\n"
                   "Currently ASFView does not read the codec-specific information.\n"
                   "You can decode that from the hexdumps manually if you want.\n");
        }
        return(0);
    }

    //open the file:
    filehandle = fopen( filename, "rb+");
    if (filehandle==NULL)
    {
        printf("Unable to open file %s\n", filename);
        return 0;
    }

    printf("output for file %s:\n",filename);
    while(1)
    {
        //really should be an EOF check, but havn't implimented it yet :-)
        printf("   Object %d\n", object);
        object++;
        fread(&GUID, 1, 16, filehandle);
        guidfix(GUID);
        printf("      GUID:\n      ");
        for(n=0;n<16;n++)
        {
            printf("%1.2X",GUID[n]);
            if ((n==3)||(n==5)||(n==7)||(n==9))
                printf("-");
        }
        printf("\n");
        //Now for the difficult part. The GUID has been read, and now identifies the object
        //But what comes next? The GUID must be checked and the appropriate info read and displayed.
        //This is the messist code in here.
        recognised=0;
        if(guidcomp(GUID, ASF_header_object)&&recognised==0)
        {
            header_object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_Content_Description_Object)&&recognised==0)
        {
            content_description_object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_Extended_Content_Description_Object)&&recognised==0)
        {
            Extended_Content_Description_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_Stream_Bitrate_Properties_Object)&&recognised==0)
        {
            Stream_Bitrate_Properties_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_File_Properties_Object)&&recognised==0)
        {
            File_Properties_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_Header_Extension_Object)&&recognised==0)
        {
            Header_Extension_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_Stream_Properties_Object)&&recognised==0)
        {
            Stream_Properties_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_Codec_List_Object)&&recognised==0)
        {
            Codec_List_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_Marker_Object)&&recognised==0)
        {
            Marker_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_Script_Command_Object)&&recognised==0)
        {
            Script_Command_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_Language_List_Object)&&recognised==0)
        {
            Language_List_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_Padding_Object)&&recognised==0)
        {
            Padding_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_DRMv1_Header_Object)&&recognised==0)
        {
            DRMv1_Header_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_DRMv2_Header_Object)&&recognised==0)
        {
            DRMv2_Header_Object();
            recognised=-1;
        }
        if(guidcomp(GUID, ASF_Data_Object)&&recognised==0)
        {
            printf("      ASF Data Object\n      End of header, program finished successfully.\n");
            return(0);
        }
        if(recognised==0)
        {
            printf("Error: unrecognised GUID.\n");
            Unknown_Object();  //really buggy, sends the program into a loop because it doesn't always read the size correctly. Its a 64-bit thing.
            //return(0);//debug
        }
    }
    //If this code executes something is very wrong, the file has ended without data!
    //Actually this code cant execute at all until I impliment the EOF check above.
    printf("Premature end of file!\n");
    printf("This should not happen. The file has ended without an ASF data object. Its nothing but a header!\n");
    printf("It it possible the file is damaged\n");
    fclose(filehandle);
    return(0);
}




void guidfix(unsigned char GUID[16])
{
    unsigned char c;
    //The GUID is used to identify sections of the ASF file.
    //The bytes are not stored in the right order.
    //So they need to be swaped round.
    c=GUID[0];GUID[0]=GUID[3];GUID[3]=c;
    c=GUID[1];GUID[1]=GUID[2];GUID[2]=c;
    c=GUID[4];GUID[4]=GUID[5];GUID[5]=c;
    c=GUID[6];GUID[6]=GUID[7];GUID[7]=c;
}

int guidcomp(unsigned char alpha[16], unsigned char beta[16])
{
    //This function compares two GUIDs, returns 1 if match, 0 if not.
    //It's a lot like memcmp, except I had a little trouble with that at first. Endian issues. Could just rewrite to use memcmp now I know why, but... meh.
    int n;//loop
    for(n=0;n<16;n++)
    {
        if(alpha[n]!=beta[n])
            return 0;
    }
    return 1;
}

void header_object()
{
    int n;//loop

    printf("      Header object\n");
    fread(&int64, 1, 8, filehandle);
    printf("      Object size                                :%llu\n", int64);
    fread(&int32, 1, 4, filehandle);
    printf("      Number of header objects                   :%u\n", int32);
    fread(&byte, 1, 1, filehandle);
    printf("      reserved1 (should be 0x01)                 :%1.2x\n", byte);
    if(byte!=0x01)
        printf("      Reserved1 field value wrong! This should not affect player.\n");
    fread(&byte, 1, 1, filehandle);
    printf("      reserved2 (should be 0x02)                 :%1.2x\n", byte);
    if(byte!=0x02)
        printf("      reserved2 field value wrong! Player will not accept file.\n");
}

void content_description_object()
{
    unsigned int n;
    uint16_t title_len=0;
    uint16_t auth_len=0;
    uint16_t copy_len=0;
    uint16_t desc_len=0;
    uint16_t rate_len=0;
    printf("      Content description object\n");
    fread(&int64, 8, 1, filehandle);
    printf("      Object size                                :%llu\n", int64);
    fread(&title_len, 1, 2, filehandle);
    fread(&auth_len, 1, 2, filehandle);
    fread(&copy_len, 1, 2, filehandle);
    fread(&desc_len, 1, 2, filehandle);
    fread(&rate_len, 1, 2, filehandle);
    printf("      Title Length(bytes)                        :%d\n", title_len);
    printf("      Author Length(bytes)                       :%d\n", auth_len);
    printf("      Copyright Length(bytes)                    :%d\n", copy_len);
    printf("      Description Length(bytes)                  :%d\n", desc_len);
    printf("      Rateing Length(bytes)                      :%d\n", rate_len);
    printf("      title                                      :");
    for(n=0;n<title_len;n++)
        fread(&byte, 1, 1, filehandle);printf("%c", byte);
    printf("\n");
    printf("      Author                                     :");
    for(n=0;n<auth_len;n++)
        fread(&byte, 1, 1, filehandle);printf("%c", byte);
    printf("\n");
    printf("      Copyright                                  :");
    for(n=0;n<copy_len;n++)
        fread(&byte, 1, 1, filehandle);printf("%c", byte);
    printf("\n");
    printf("      description                                :");
    for(n=0;n<desc_len;n++)
        fread(&byte, 1, 1, filehandle);printf("%c", byte);
    printf("\n");
    printf("      rate                                       :");
    for(n=0;n<rate_len;n++)
        fread(&byte, 1, 1, filehandle);printf("%c", byte);
    printf("\n");
}

void Extended_Content_Description_Object()
{
    unsigned int n;
    unsigned int m;
    unsigned int o;
    uint16_t desc_count=0;
    uint16_t name_len=0;
    uint16_t val_length=0;
    uint16_t datatype=0;
    printf("      Extended Content Description Object\n");
    fread(&int64, 8, 1, filehandle);
    printf("      Object size                                :%llu\n", int64);
    fread(&desc_count, 2, 1, filehandle);
    printf("      Content descriptors count                  :%d\n\n", desc_count);
    for(n=0;n<desc_count;n++)
    {
        fread(&name_len, 2, 1, filehandle);
        printf("         Field name length                       :%d\n", name_len);
        printf("         Field name                              :");
        for(m=0;m<name_len; m++)
        {
            fread(&byte, 1, 1, filehandle);
            printf("%c", byte);
        }
        // Alternative print mechanism (Goes wrong with some non-16bit characters. Printing with above method might not print some unicode correctly, but it wont crash either.)
        //   printf("         Field name (unicode)                    :");
        //   unicode_print(name_len/2);
        printf("\n");
        fread(&datatype, 2, 1, filehandle);
        printf("         Field data type                         :%1.4x\n",datatype);
        fread(&val_length, 2, 1, filehandle);
        printf("         Field data length                       :%d\n", val_length);

        switch(datatype)
        {
            case 0x0000:
                //You can put the above unicode_print call in here too, but the same problem will occur for some times.
                printf("         (unicode string)                        :");
                for(o=0;o<val_length;o++)
                {
                    fread(&byte, 1, 1, filehandle);
                    printf("%c", byte);
                }
                printf("\n");
                break;
            case 0x0001:
                printf("         (Byte array)                            :\n");
                int64=val_length;
                hexdump(int64);
                break;
            case 0x0002:
                fread(&int32, 4, 1, filehandle);
                printf("         (Bool)                                  :%u\n", int32);
                break;
            case 0x0003:
                fread(&int32, 4, 1, filehandle);
                printf("         (DWORD)                                 :%u\n", int32);
                break;
            case 0x0004:
                fread(&int64, 8, 1, filehandle);
                printf("         (DWORD)                                 :%llu\n", int64);
                break;
            case 0x0005:
                fread(&int16, 2, 1, filehandle);
                printf("         (DWORD)                                 :%u\n", int16);
                break;
            default:
                printf("         (Unknown datatype)                      :");
                hexdump(val_length);
                break;
        }

        /*
        if(datatype==0x0001)
        {
            printf("         (Byte array)                            :\n");
            int64=val_length;
            hexdump(int64);
        }
        if(datatype==0x0002)
        {
            fread(&int32, 4, 1, filehandle);
            printf("         (Bool)                                  :%u\n");
        }
        if(datatype==0x0003)
        {
            fread(&int32, 4, 1, filehandle);
            printf("         (DWORD)                                 :%u\n");
        }
        if(datatype==0x0004)
        {
            fread(&int64, 8, 1, filehandle);
            printf("         (DWORD)                                 :%u\n");
        }
        if(datatype==0x0005)
        {
            fread(&int16, 2, 1, filehandle);
            printf("         (DWORD)                                 :%u\n");
        }
        */
        printf("\n");
    }
}

void Stream_Bitrate_Properties_Object()
{
    uint16_t obj_count=0;
    unsigned int n;
    printf("      Stream Bitrate Properties Object\n");
    fread(&int64, 8, 1, filehandle);
    printf("      Object size                                :%llu\n", int64);
    fread(&obj_count, 1, 2, filehandle);
    printf("      Bitrate Records count                      :%u\n\n", obj_count);
    for(n=0;n<obj_count;n++)
    {
        fread(&word, 1, 2, filehandle);
        printf("      flags                                      :%1.2x%1.2x\n", word[0], word[1]);
        byte=word[0]&0x7F; //please work...This will never work.
        printf("        stream number                            :%u\n", byte);
        fread(&int32, 1, 4, filehandle);
        printf("      Average bitrate                            :%u\n\n", int32);
    }

}

void File_Properties_Object()
{
    unsigned int n;
    unsigned char fileID[16];
    unsigned char GUID[16]; //128-bit
    printf("      File Properties Object\n");
    fread(&int64, 8, 1, filehandle);
    printf("      Object size                                :%llu\n", int64);
    printf("      File ID                                    :");
    fread(&fileID, 1, 16, filehandle);
    guidfix(fileID);
    for(n=0;n<16;n++)
    {
        printf("%1.2X",fileID[n]);
        if ((n==3)||(n==5)||(n==7)||(n==9))
            printf("-");
    }
    printf("\n");
    fread(&int64, 1, 8, filehandle);
    printf("      File size (bytes)                          :%llu\n", int64);
    printf("      Creation date/time (raw)                   :");
    fread(&qword, 1, 8, filehandle);
    for(n=0;n<8;n++)
        printf("%1.2x", qword[n]);
    printf("\n");
    fread(&int64, 1, 8, filehandle);
    printf("      data packets                               :%llu\n", int64);
    fread(&int64, 1, 8, filehandle);
    printf("      play time (100 nanosecond units)           :%llu\n", int64);
    fread(&int64, 1, 8, filehandle);
    printf("      send time (100 nanosecond units)           :%llu\n", int64);
    fread(&int64, 1, 8, filehandle);
    printf("      Preroll (ms)                               :%llu\n", int64);
    fread(&dword, 1, 4, filehandle);
    printf("      Flags                                      :%1.2X%1.2X%1.2X%1.2X\n\n", dword[0], dword[1], dword[2], dword[3]);
    fread(&int32, 1, 4, filehandle);
    printf("      Minimum data packet size                   :%u\n", int32);
    fread(&int32, 1, 4, filehandle);
    printf("      Maximum data packet size                   :%u\n", int32);
    fread(&int32, 1, 4, filehandle);
    printf("      Maximum bitrate (bits/sec)                 :%u\n", int32);
}

void Header_Extension_Object()
{
    unsigned int n;
    printf("      Header Extension Object\n");
    fread(&int64, 1, 8, filehandle);
    printf("      Object size (Always 46 in this object)     :%llu\n", int64);
    printf("      Reserved 1                                 :");
    fread(&GUID, 1, 16, filehandle);
    guidfix(GUID);
    for(n=0;n<16;n++)
    {
        printf("%1.2X",GUID[n]);
        if ((n==3)||(n==5)||(n==7)||(n==9))
            printf("-");
    }
    printf("\n");
    fread(&word, 1, 2, filehandle);
    printf("      Reserved 2                                 :%1.2X, %1.2X\n", word[0], word[1]);
    int32=0;
    fread(&int32, 1, 4, filehandle);
    printf("      Header extension data size                 :%u\n\n", int32);
}

void Stream_Properties_Object()
{
    unsigned int n;
    uint32_t datatype_len;
    uint32_t errcor_len;
    unsigned int stream_num;
    unsigned int encrypted_content;
    printf("      Stream Properties Object\n");
    fread(&int64, 1, 8, filehandle);
    printf("      Object size                                :%llu\n", int64);
    printf("      Stream type                                :");
    fread(&GUID, 1, 16, filehandle);
    guidfix(GUID);
    for(n=0;n<16;n++)
    {
        printf("%1.2X",GUID[n]);
        if ((n==3)||(n==5)||(n==7)||(n==9))
            printf("-");
    }
    printf("\n");
    printf("      Error correction type                      :");
    fread(&GUID, 1, 16, filehandle);
    guidfix(GUID);
    for(n=0;n<16;n++)
    {
        printf("%1.2X",GUID[n]);
        if ((n==3)||(n==5)||(n==7)||(n==9))
            printf("-");
    }
    printf("\n");
    fread(&int64, 1, 8, filehandle);
    printf("      Time offset (100nanosecond units)          :%llu\n", int64);
    fread(&datatype_len, 1, 4, filehandle);
    printf("      Type-specific data length                  :%u\n", datatype_len);
    fread(&errcor_len, 1, 4, filehandle);
    printf("      Error-correction data length               :%u\n", errcor_len);
    fread(&word, 1, 2, filehandle);
    printf("      Flags                                      :%1.2X, %1.2X\n", word[0], word[1]);
    stream_num=word[0]&0x7F;
    printf("         Stream number                           :%u\n", stream_num);
    encrypted_content=word[1]&0x80;
    if(encrypted_content)
        printf("         Encrypted content                       :yes :-(\n");
    else
        printf("         Encrypted content                       :no\n");
    fread(&dword, 1, 4, filehandle);
    printf("      Reserved (should be zero)                  :%1.2X%1.2X%1.2X%1.2X\n", dword[0], dword[1], dword[2], dword[3]);
    printf("      Type-specific data (hexdump)               :\n");
    int64=datatype_len;  //hexdump doesn't work unless the arguement is uint64_t
    hexdump(int64);
    printf("      Error-correction data (hexdump)            :\n");
    int64=errcor_len;
    hexdump(int64);
}

void hexdump(uint64_t remaining)
{
    //This routine gives a neat hex code listing of the file :-)
    //The remaining parameter specifies the length of file to dump.

    unsigned char buffer[16];
    int position; //loop
    int n; //another loop
    int m; //yet another loop

    while(remaining>0)
    {
        if(remaining>16)
        {
            n=16;
            remaining=remaining-16;
        }
        else
        {
            n=remaining;
            remaining=0;
        }

        fread(&buffer, 1, n, filehandle);
        printf("        ");
        for(position=0;position<n;position++)
        {
            printf("%1.2X ", buffer[position]);
        }
        printf("         ");
        if(n<16)
            for(m=n;m<16;m++)
                printf("   ");
        for(position=0;position<n;position++)
        {
            if(buffer[position]>32 & buffer[position]<0x7f) //Extended ascii is hidden for compatability.
                printf("%c", buffer[position]);  //displayable characters
            else
                printf(".");  //non-displayable characters
        }
        printf("\n");
  }
  printf("\n");
}

void Codec_List_Object()
{
    int n;
    uint32_t codecs;
    int m;
    printf("      Codec list object\n");
    fread(&int64, 1, 8, filehandle);
    printf("      Object size                                :%llu\n", int64);
    printf("      Reserved field                             :");
    fread(&GUID, 1, 16, filehandle);
    guidfix(GUID);
    for(n=0;n<16;n++)
    {
        printf("%1.2X",GUID[n]);
        if ((n==3)||(n==5)||(n==7)||(n==9))
            printf("-");
    }
    printf("\n");
    int32=0;  //Does the format really need to support 2^32 codec enteries?
    fread(&codecs, 1, 4, filehandle);
    printf("      Codec enteries count                       :%u\n\n", codecs);
    for(n=1;n<=codecs;n++)
    {
        fread(&word, 1, 2, filehandle);
        printf("\n        Type                                     :%1.2X%1.2X\n", word[1], word[0]);

        int16=0;
        fread(&int16, 2, 1, filehandle);
        printf("        Codec name length                        :%u\n", int16);
        printf("        Codec name                               :");
        int64=int16;
        unicode_print(int64);

        int16=0;
        fread(&int16, 2, 1, filehandle);
        printf("        Codec description length                 :%u\n", int16);
        printf("        Codec description                        :");
        int64=int16;
        unicode_print(int64);

        int16=0;
        fread(&int16, 2, 1, filehandle);
        printf("        Codec information length                 :%u\n", int16);
        printf("        Codec information (hexdump)              :\n");
        int64=int16;
        hexdump(int64);
    }
}

void unicode_print(int remaining)
{
    //I hate unicode! What was wrong with ascii? eight bits per character, just as it should be.
    //remaining holds the number of characters (not bytes) to display.
    int n;
    for(n=1;n<=remaining;n++)
    {
        fread(&word, 2, 1, filehandle); //My hex editor says each character consists of a null byte, then a standard ascii character. This isn't always true - if you try to read anything with japanese text, expect dramatic failure.
        printf("%c", word[0]);
    }
    printf("\n");

}


void Marker_Object()
{
    uint32_t n;
    uint32_t markers;
    uint16_t entry_len;
    printf("   Marker Object:\n");

    fread(&int64, 1, 8, filehandle);
    printf("      Object size                                :%llu\n", int64);
    printf("      Reserved field                             :");
    fread(&GUID, 1, 16, filehandle);
    guidfix(GUID);
    for(n=0;n<16;n++)
    {
        printf("%1.2X",GUID[n]);
        if ((n==3)||(n==5)||(n==7)||(n==9))
            printf("-");
    }
    printf("\n");
    fread(&markers, 1, 4, filehandle);
    printf("      Markers count                              :%u\n", markers);
    fread(&int16, 1, 2, filehandle);
    printf("      Reserved (should be zero)                  :%u\n", int16);
    fread(&int16, 1, 2, filehandle);
    printf("      Name length                                :%u\n", int16);
    printf("      Name                                       :");
    for(n=0;n<int16;n++)
    {
        fread(&byte, 1, 1, filehandle);
        printf("%c", byte);
    }
    printf("\n");
    for(n=0;n<markers;n++)
    {
        printf("      Marker %u:\n", n);
        fread(&int64, 1, 8, filehandle);  //The only good thing about ASF - it supports large files. Not large enough for raw video through :-).
        printf("         Offset                                  :%llu\n", int64);
        fread(&int64, 1, 8, filehandle);
        printf("         Presentation time (100ns units)         :%llu\n", int64);
        fread(&entry_len, 1, 2, filehandle);
        printf("         Entry length                            :%u\n", entry_len);
        entry_len=entry_len-12; //length of the three DWORDS send time, flags, and marker description length
        fread(&int32, 1, 4, filehandle);
        printf("         Send time (ms)                          :%u\n", int32);
        fread(&dword, 1, 4, filehandle);
        printf("         Flags (should all be zero)              :%1.2X%1.2X%1.2X%1.2X\n", dword[0], dword[1], dword[2], dword[3]);
        fread(&int32, 1, 4, filehandle);
        printf("         Marker description length               :%u\n", int32);
        entry_len=entry_len-int32; //It seems odd to make marker_description_length 32 bit, but entry_length 16 bit, when entry_length must be greater than marker_description_length. But this is microsofts format, so it doesn't need to make sense. They could specify 2k of the file must contain a bitmap of the windows media logo and they could still become the dominant format
        printf("         Marker Description                      :\n");
        int64=int32;
        hexdump(int64);//This is usually a string, but not always, and it can be ascii or unicode. Instead of trying to handle all those I will just hexdump.
        int64=entry_len;
        printf("         Padding bytes                           :%llu\n", int64);
        hexdump(int64);

    }
    //Somehow, dispite being full of bugs, this routine somehow works. I think the bugs cancel out.
}

void Script_Command_Object()
{
    printf("      Script Command Object:\n");
    printf("Not implimented, treating as unknown.\n");
    Unknown_Object();
}

void Language_List_Object()
{
    printf("      Language List Object:\n");
    printf("      Not implimented, treating as unknown.\n");
    Unknown_Object();
}

void Padding_Object()
{
    printf("      Padding Object:\n");
    int64=0;
    fread(&int64, 1, 8, filehandle);
    printf("      Object size                                :%llu\n", int64);
    printf("      Raw dump of object (Should be all nulls - reading software ignores):\n");
    int64=int64-24;
    hexdump(int64);
    printf("\n");
}

void DRMv1_Header_Object()
{
    uint32_t n;

    printf("      DRMv1 Header Object\n");

    int64=0;
    fread(&int64, 1, 8, filehandle);
    printf("      Object size                                :%llu\n", int64);

    int32=0;
    fread(&int32, 1, 4, filehandle);
    printf("      Unknown Object length                      :%u\n", int32);
    printf("      Unknown Object (hexdump)                   :\n");
    int64=int32;
    hexdump(int64);

    int32=0;
    fread(&int32, 1, 4, filehandle);
    printf("      Unknown String                             :");
    for(n=0;n<int32;n++)
    {
        fread(&byte, 1, 1, filehandle);
        printf("%c", byte);
    }
    printf("\n");

    int32=0;
    fread(&int32, 1, 4, filehandle);
    printf("      KeyID                                      :");
    for(n=0;n<int32;n++)
    {
        fread(&byte, 1, 1, filehandle);
        printf("%c", byte);
    }
    printf("\n");

    int32=0;
    fread(&int32, 1, 4, filehandle);
    printf("      LicenseAcqURL                              :");
    for(n=0;n<int32;n++)
    {
        fread(&byte, 1, 1, filehandle);
        printf("%c", byte);
    }
    printf("\n");

    printf("\n");
}

void DRMv2_Header_Object()
{
    printf("      DRMv2 Header Object\n");

    int64=0;
    fread(&int64, 1, 8, filehandle);
    printf("      Object size                                :%llu\n", int64);

    int32 = 0;
    fread(&int32, 1, 4, filehandle);
    printf("      DRMv2 XML Object length                    :%u\n", int32);
    printf("      DRMv2 XML Object (hex dump)                :\n");
    int64=int32;
    hexdump(int64);
}

void Unknown_Object()
{
    //What is this? An unknown header object? Or a skipped byte somewhere?
    //If its an unknown header object the first field after the GUID will be a qword, its size. Read and skip!
    //Give the user a hex dump too. They might know what to do with it.
    printf("   UNKNOWN OBJECT!!!!\n");
    int64=0;
    fread(&int64, 1, 8, filehandle);
    printf("      Object size                                :%llu\n", int64);
    int64=int64-24;
    hexdump(int64);
    printf("\n   End of unknown object.\n");
}
